﻿using AutoMapper;
using Common;
using Common.DataModels;
using MediatR;
using Microsoft.EntityFrameworkCore;
using PLC.Domain.Dto;
using PLC.Domain.Entity;
using PLC.Domain.Enum;
using PLC.Domain.Models;
using PLC.Domain.Service.IRepository;

namespace PLC.Domain.Service.Service;

public class ProductionDataService
{
    private readonly IMapper _mapper;
    private readonly IProductionDataRepository _productionDataRepository;
    private readonly IAirtightDataRepository _airtightDataRepository;
    private readonly IRepairAirtightDataRepository _repairAirtightDataRepository;
    private readonly IPressureDataRepository _pressureDataRepository;
    private readonly IBarcodeDataRepository _barcodeDataRepository;
    private readonly IDeviceStatusRepository _deviceStatusRepository;
    private readonly IDeviceConfigRepository _deviceConfigRepository;
    private readonly IMediator _mediator;

    public ProductionDataService(IMapper mapper,
        IProductionDataRepository productionDataRepository,
        IAirtightDataRepository airtightDataRepository,
        IRepairAirtightDataRepository repairAirtightDataRepository,
        IPressureDataRepository pressureDataRepository,
        IBarcodeDataRepository barcodeDataRepository,
        IDeviceStatusRepository deviceStatusRepository,
        IDeviceConfigRepository deviceConfigRepository,
        IMediator mediator)
    {
        _mapper = mapper?? throw new ArgumentNullException(nameof(mapper));
        _productionDataRepository = productionDataRepository?? throw new ArgumentNullException(nameof(productionDataRepository));
        _airtightDataRepository = airtightDataRepository?? throw new ArgumentNullException(nameof(airtightDataRepository));
        _repairAirtightDataRepository = repairAirtightDataRepository?? throw new ArgumentNullException(nameof(repairAirtightDataRepository));
        _pressureDataRepository = pressureDataRepository ?? throw new ArgumentNullException(nameof(pressureDataRepository));
        _barcodeDataRepository = barcodeDataRepository?? throw new ArgumentNullException(nameof(barcodeDataRepository));
        _deviceStatusRepository = deviceStatusRepository?? throw new ArgumentNullException(nameof(deviceStatusRepository));
        _deviceConfigRepository = deviceConfigRepository?? throw new ArgumentNullException(nameof(deviceConfigRepository));
        _mediator = mediator?? throw new ArgumentNullException(nameof(mediator));
    }

    /// <summary>
    /// 分页查询(值查询装堆机装上了的数据)
    /// </summary>
    /// <param name="pagingModel"></param>
    /// <param name="taskCode"></param>
    /// <param name="upperEndPlateCode"></param>
    /// <param name="lowerEndPlateCode"></param>
    /// <param name="starTime"></param>
    /// <param name="endTime"></param>
    /// <returns></returns>
    public virtual async Task<Tuple<List<DtoProductionData>, int>> FindByPageAsync(PagingModel pagingModel,string taskCode ,string upperEndPlateCode, string lowerEndPlateCode, DateTime starTime, DateTime endTime)
    {
        var query = _productionDataRepository.Qyery.Where(p => !p.IsDelete&&p.DeviceType==(int)EnumDeviceType.装堆机);
        if (!string.IsNullOrWhiteSpace(upperEndPlateCode))
        {
            query = query.Where(p => p.UpperEndPlateCode.Contains(upperEndPlateCode) );
        }

        if (!string.IsNullOrWhiteSpace(lowerEndPlateCode))
        {
            query = query.Where(p => p.LowerEndPlateCode.Contains(lowerEndPlateCode) );
        }

        if (!string.IsNullOrWhiteSpace(taskCode))
        {
            query = query.Where(p => p.TaskCode.Contains(taskCode));
        }
        if (starTime != default)
        {
            query = query.Where(p => p.CreateTime >= starTime);
        }

        if (endTime != default)
        {
            query = query.Where(p => p.CreateTime <= endTime);
        }
        if (!string.IsNullOrWhiteSpace(pagingModel.sort))
        {
            query = query.OrderByDynamic(pagingModel.sort);
        }
        // 根据上下底板来去重
        var count = await query.CountAsync();
        var data = await query.Skip((pagingModel.page-1)*pagingModel.rows).Take(pagingModel.rows).ToListAsync();
        return new Tuple<List<DtoProductionData>, int>(_mapper.Map<List<DtoProductionData>>(data), count);
    }
    /// <summary>
    /// 查询产品的压堆机数据
    /// </summary>
    /// <param name="page"></param>
    /// <param name="rows"></param>
    /// <param name="sort"></param>
    /// <param name="upperEndPlateCode"></param>
    /// <param name="lowerEndPlateCode"></param>
    /// <returns></returns>
    public virtual async Task<(IList<DtoPressureData> data, int count)> FindStackerDataByCodeAsync(int page,int rows,string sort,
        string upperEndPlateCode, string lowerEndPlateCode)
    {
        var query = _pressureDataRepository.Qyery.Where(p => !p.IsDelete);
        if (!string.IsNullOrWhiteSpace(upperEndPlateCode))
        {
            query = query.Where(p => p.UpperEndPlateCode == upperEndPlateCode);
        }
        if (!string.IsNullOrWhiteSpace(lowerEndPlateCode))
        {
            query = query.Where(p => p.LowerEndPlateCode == lowerEndPlateCode);
        }
        var count = await query.CountAsync();
        if (!string.IsNullOrWhiteSpace(sort))
        {
            query = query.OrderByDynamic(sort);
        }
        var data = await query.AsNoTracking().Skip((page-1)*rows).Take(rows).ToListAsync();
        var list = new List<DtoPressureData>(data.Count);
        foreach (var item in data)
        {
            var dto = _mapper.Map<DtoPressureData>(item);
            if (!string.IsNullOrWhiteSpace(dto.Data))
            {
                var plcDataModels = JsonHelper.DeserializeObject<List<PLCDataModel>>(dto.Data);
                dto.Position = plcDataModels.FirstOrDefault(p =>!string.IsNullOrWhiteSpace(p.Description)&& p.Description.Contains("下压"))?.Value ?? "";
                dto.Pressure  = plcDataModels.FirstOrDefault(p =>!string.IsNullOrWhiteSpace(p.Description)&&p.Description.Contains("压力"))?.Value ?? "";
            }
            list.Add(dto);
        }
        return (list,count);
    }
    /// <summary>
    /// 查询对应的膜电极和双极板的条码信息
    /// </summary>
    /// <param name="page"></param>
    /// <param name="rows"></param>
    /// <param name="sort"></param>
    /// <param name="upperEndPlateCode"></param>
    /// <param name="lowerEndPlateCode"></param>
    /// <param name="deviceId"></param>
    /// <returns></returns>
    public virtual async Task<(IList<DtoBarcodeData> data, int count)> FindBarCodeByCodeAsync(int page, int rows,string sort,
        string upperEndPlateCode, string lowerEndPlateCode,int deviceType)
    {
        var query = _barcodeDataRepository.Qyery.Where(p => !p.IsDelete);
        if (!string.IsNullOrWhiteSpace(upperEndPlateCode))
        {
            query = query.Where(p => p.UpperEndPlateCode == upperEndPlateCode);
        }

        if (!string.IsNullOrWhiteSpace(lowerEndPlateCode))
        {
            query = query.Where(p => p.LowerEndPlateCode == lowerEndPlateCode);
        }

        if (deviceType!=default)
        {
            query = query.Where(p => p.DeviceType == deviceType);
        }
        var count = await query.CountAsync();
        if (!string.IsNullOrWhiteSpace(sort))
        {
            query = query.OrderByDynamic(sort);
        }
        var data = await query.AsNoTracking().Skip((page - 1) * rows).Take(rows).ToListAsync();
        // 数据组装
        var membraneElectrodes = data.Where(p => !string.IsNullOrWhiteSpace(p.MembraneElectrode)&&p.MembraneElectrode.Length>=1)
            .Select(p => p.MembraneElectrode).ToList();
        var bipolarPlates = data.Where(p => !string.IsNullOrWhiteSpace(p.BipolarPlate)&&p.BipolarPlate.Length>=1).Select(p => p.BipolarPlate)
            .ToList();
        var barcodeList = new List<DtoBarcodeData>();
        for (int i = 0; i <Math.Max(membraneElectrodes.Count,bipolarPlates.Count); i++)
        {
            var dto = new DtoBarcodeData();
            if (membraneElectrodes.Count>i)
            {
                dto.SetMembraneElectrode(membraneElectrodes[i]);
            }

            if (bipolarPlates.Count>i)
            {
                dto.SetBipolarPlate(bipolarPlates[i]);
            }
            barcodeList.Add(dto);
        }
        return (barcodeList,barcodeList.Count);
    }
    /// <summary>
    /// 根据设备类别和上下端板码来获取设备数据
    /// </summary>
    /// <param name="deviceType"></param>
    /// <param name="upperEndPlateCode"></param>
    /// <param name="lowerEndPlateCode"></param>
    /// <returns></returns>
    public async Task<DtoProductionData> FindOneByDeviceType(int deviceType, string upperEndPlateCode,
        string lowerEndPlateCode)
    {
        var query = _productionDataRepository.Qyery.Where(p => !p.IsDelete&&p.DeviceType==deviceType);
        if (!string.IsNullOrWhiteSpace(upperEndPlateCode))
        {
            query = query.Where(p => p.UpperEndPlateCode == upperEndPlateCode);
        }

        if (!string.IsNullOrWhiteSpace(lowerEndPlateCode))
        {
            query = query.Where(p => p.LowerEndPlateCode == lowerEndPlateCode);
        }

        var data = await query.OrderByDescending(p => p.CreateTime).FirstOrDefaultAsync();
        return _mapper.Map<DtoProductionData>(data);
    }

    //数据类型(1:装堆机压力,2:气密，3：维修气密)
    /// <summary>
    /// 获取过程数据
    /// </summary>
    /// <param name="pagingModel"></param>
    /// <param name="upperEndPlateCode"></param>
    /// <param name="lowerEndPlateCode"></param>
    /// <param name="type"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public virtual  Task<Tuple<List<DtoAirtightData>,int>> FindProcessData(PagingModel pagingModel, string upperEndPlateCode,
        string lowerEndPlateCode, int type)
    {
        if (type==(int)EnumDeviceType.气密检测)// 气密
        {
            return GetAirtightData(pagingModel, upperEndPlateCode, lowerEndPlateCode);
        }else if (type==(int)EnumDeviceType.维修检测)// 维修
        {
            return GetRepairAirtightData(pagingModel, upperEndPlateCode, lowerEndPlateCode);
        }
        else
        {
            throw new Exception("没有对应的type类型的处理");
        }
    }
    /// <summary>
    /// 获取压力过程数据
    /// </summary>
    /// <param name="pagingModel"></param>
    /// <param name="upperEndPlateCode"></param>
    /// <param name="lowerEndPlateCode"></param>
    /// <returns></returns>
    private async Task<Tuple<List<DtoAirtightData>, int>> GetPressureData(PagingModel pagingModel, string upperEndPlateCode,
        string lowerEndPlateCode)
    {
        var expression = ExpressionExtensions.True<PressureData>().And(p => !p.IsDelete);
        if (!string.IsNullOrWhiteSpace(upperEndPlateCode))
        {
            expression = expression.And(p => p.UpperEndPlateCode == upperEndPlateCode);
        }

        if (!string.IsNullOrWhiteSpace(lowerEndPlateCode))
        {
            expression = expression.And(p => p.LowerEndPlateCode == lowerEndPlateCode);
        }
        var data = await _pressureDataRepository.GetEntitiesByPageAsync(expression, pagingModel.sort, pagingModel.page, pagingModel.rows);
        return new Tuple<List<DtoAirtightData>, int>(_mapper.Map<List<DtoAirtightData>>(data.Item1), data.Item2);
    }

    /// <summary>
    /// 获取气密过程数据
    /// </summary>
    /// <param name="pagingModel"></param>
    /// <param name="upperEndPlateCode"></param>
    /// <param name="lowerEndPlateCode"></param>
    /// <returns></returns>
    private async Task<Tuple<List<DtoAirtightData>, int>> GetAirtightData(PagingModel pagingModel, string upperEndPlateCode,
        string lowerEndPlateCode)
    {
        var expression = ExpressionExtensions.True<AirtightData>().And(p => !p.IsDelete);
        if (!string.IsNullOrWhiteSpace(upperEndPlateCode))
        {
            expression = expression.And(p => p.UpperEndPlateCode == upperEndPlateCode);
        }

        if (!string.IsNullOrWhiteSpace(lowerEndPlateCode))
        {
            expression = expression.And(p => p.LowerEndPlateCode == lowerEndPlateCode);
        }
        var data = await _airtightDataRepository.GetEntitiesByPageAsync(expression, pagingModel.sort, pagingModel.page, pagingModel.rows);
        return new Tuple<List<DtoAirtightData>, int>(_mapper.Map<List<DtoAirtightData>>(data.Item1), data.Item2);
    }
    /// <summary>
    /// 获取维修气密过程数据
    /// </summary>
    /// <param name="pagingModel"></param>
    /// <param name="upperEndPlateCode"></param>
    /// <param name="lowerEndPlateCode"></param>
    /// <returns></returns>
    private async Task<Tuple<List<DtoAirtightData>, int>> GetRepairAirtightData(PagingModel pagingModel, string upperEndPlateCode,
        string lowerEndPlateCode)
    {
        var expression = ExpressionExtensions.True<RepairAirtightData>().And(p => !p.IsDelete);
        if (!string.IsNullOrWhiteSpace(upperEndPlateCode))
        {
            expression = expression.And(p => p.UpperEndPlateCode == upperEndPlateCode);
        }

        if (!string.IsNullOrWhiteSpace(lowerEndPlateCode))
        {
            expression = expression.And(p => p.LowerEndPlateCode == lowerEndPlateCode);
        }
        var data = await _repairAirtightDataRepository.GetEntitiesByPageAsync(expression, pagingModel.sort, pagingModel.page, pagingModel.rows);
        return new Tuple<List<DtoAirtightData>, int>(_mapper.Map<List<DtoAirtightData>>(data.Item1), data.Item2);
    }

    /// <summary>
    /// 更新
    /// </summary>
    /// <param name="entity"></param>
    /// <returns></returns>
    public virtual async Task<DtoProductionData> UpdateAsync(DtoProductionData entity)
    {
        var barcodeData = await _productionDataRepository.GetEntityAsync(p => p.Id == entity.Id && !p.IsDelete);
        ArgumentNullException.ThrowIfNull(barcodeData);
        _mapper.Map(entity, barcodeData);
        await _productionDataRepository.UpdateAsync(barcodeData);
        return entity;
    }
    /// <summary>
    /// 精确查询
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public virtual async Task<DtoProductionData> FindOneAsync(long id)
    {
        var data = await _productionDataRepository.GetEntityAsync(p => p.Id == id && !p.IsDelete);
        ArgumentNullException.ThrowIfNull(data);
        return _mapper.Map<DtoProductionData>(data);
    }
    /// <summary>
    /// 新增
    /// </summary>
    /// <param name="entity"></param>
    /// <returns></returns>
    public virtual async Task<DtoProductionData> CreateAsync(DtoProductionData entity)
    {
        ArgumentNullException.ThrowIfNull(nameof(entity));
        // 需要根据devicetype来找到对应的设备的id  来组装productionData
        var config = await _deviceConfigRepository.GetEntityAsync(p => !p.IsDelete&&p.DeviceType==entity.DeviceType);
        ArgumentNullException.ThrowIfNull(config);
        entity.DeviceId = config.DeviceId;
        var data = _mapper.Map<ProductionData>(entity).Build();
        await _productionDataRepository.CreateAsync(data);
        // 把接受到的数据推送给后端
        var resultData = _mapper.Map<DtoProductionData>(data);
        await _mediator.Publish(new SendDataModel()
        {
            DtoProductionDatas = new List<DtoProductionData>()
            {
                resultData
            }
        });
        return resultData;
    }

    /// <summary>
    /// 批量插入
    /// </summary>
    /// <param name="entities"></param>
    /// <returns></returns>
    public virtual Task CreateAsync(IEnumerable<ProductionData> entities)
    {
        ArgumentNullException.ThrowIfNull(entities);
        return _productionDataRepository.CreateAsync(entities);
    }
    /// <summary>
    /// 批量插入
    /// </summary>
    /// <param name="entities"></param>
    /// <returns></returns>
    public virtual async Task CreateAsync(IEnumerable<DtoProductionData> entities)
    {
        ArgumentNullException.ThrowIfNull(entities);
        var deviceConfigs = await _deviceConfigRepository.GetEntitiesAsync(p => !p.IsDelete);
        var airtight = deviceConfigs.FirstOrDefault(p => p.DeviceName.Contains(EnumDtoDeviceType.气密.ToString()));
        var repair = deviceConfigs.FirstOrDefault(p => p.DeviceName.Contains(EnumDtoDeviceType.返修.ToString()));
        if (airtight==null||repair==null)
        {
            throw new Exception("匹配不到对应的气密和维修工站的设备id");
        }
        foreach (var entity in entities)
        {
            if (entity.DeviceType==(int)EnumDtoDeviceType.气密)
            {
                entity.DeviceId = airtight.DeviceId;
            }
            else if(entity.DeviceType==(int)EnumDtoDeviceType.返修)
            {
                entity.DeviceId = repair.DeviceId;
            }
        }
        var data = _mapper.Map<List<ProductionData>>(entities).Select(p=>p.Build()).ToList();
        await CreateAsync(data);
    }
    /// <summary>
    /// 删除
    /// </summary>
    /// <param name="ids"></param>
    /// <returns></returns>
    public virtual async Task DeleteAsync(IEnumerable<long> ids)
    {
        ArgumentNullException.ThrowIfNull(ids);
        await _productionDataRepository.Qyery.Where(p => ids.Contains(p.Id))
            .ExecuteUpdateAsync(p => p.SetProperty(o => o.IsDelete, true));
    }

    /// <summary>
    /// 获取设备状态
    /// </summary>
    /// <param name="pagingModel"></param>
    /// <param name="deviceId"></param>
    /// <param name="starTime"></param>
    /// <param name="endTime"></param>
    /// <returns></returns>
    public virtual async Task<Tuple<List<DtoDeviceStatus>, int>> FindDeviceStatus(PagingModel pagingModel, long deviceId, DateTime starTime, DateTime endTime)
    {
        if (deviceId==0)
        {
            throw new Exception("设备id错误");
        }

        var expression = ExpressionExtensions.True<DeviceStatus>().And(p => !p.IsDelete&&p.DeviceId==deviceId);
        if (starTime!=default)
        {
            expression = expression.And(p => p.CreateTime >= starTime);
        }

        if (endTime!=default)
        {
            expression = expression.And(p => p.CreateTime <= endTime);
        }

        var data =await _deviceStatusRepository.GetEntitiesByPageAsync(expression, pagingModel.page, pagingModel.rows);
        return new Tuple<List<DtoDeviceStatus>, int>(
            _mapper.Map<List<DtoDeviceStatus>>(data.Item1.OrderByDescending(p => p.CreateTime)),data.Item2);
    }
}